package com.copc.common.util;

import cn.hutool.core.util.ReflectUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.*;
import java.lang.reflect.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Time;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 工具类
 *
 * @author yuanbin
 * 判断/验证,类型的方法用is开头
 * 转换类型的方法用 convert开头
 * 添加类型的方法用add开头
 * 获取类型的方法以get开头
 * 设置类型的方法以set开头
 * 复制类型的用copy开头
 * 排序类型的方法用sort开头
 * 功能性方法用execute开头
 */
@SuppressWarnings("rawtypes")
public class CommonUtil {

    private static final Logger log = LoggerFactory.getLogger(CommonUtil.class);

    public static final String PATH_PREPARED_STATEMENT_UUID = "\\{uuid\\}";// UUID路径占位符
    public static final String PATH_PREPARED_STATEMENT_DATE = "\\{date(\\(\\w+\\))?\\}";// 日期路径占位符
    public static final String COMMON_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
    private static ObjectMapper mapper = new ObjectMapper();

    public static String convertDateToStr(Date date,String format){
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(date);
    }


    /********功能性方法用execute开头*********/
    /**
     * 字符串解密
     *
     * @param s
     * @return
     * @return?String
     * @author add by chengxw
     * @date 2013-5-31
     */
    public static String executeDecrypt(String s) {
        int iLen = 0;
        String sText = s;
        String sResult = "";
        //String sRtn = "";
        iLen = sText.length();
        for (int i = 1; i <= iLen; i++) {
            sResult = (char) (sText.substring(i - 1, i).codePointAt(0) - (2 * (iLen - i - 2))) + sResult;
        }
        return sResult;
    }

    /**
     * 字符串加密
     *
     * @param str
     * @return
     * @return?String
     * @author add by chengxw
     * @date 2013-5-31
     */
    public static String executeEncrypt(String str) {
        StringBuffer resStr = new StringBuffer();
        StringBuffer buf = new StringBuffer(str.trim());
        buf = buf.reverse();//字符串翻转
        for (int i = 1; i <= buf.length(); i++) {
            char c = (char) (((buf.substring(i - 1, i)).codePointAt(0)) + ((buf.length() - i - 2) * 2));
            resStr.append(c);
        }
        return resStr.toString();
    }

    public static void join(String before, Object append, String join) {
        if (isEmpty(before)) {
            before = append.toString();
        } else {
            before = before + join + append;
        }
    }

    public static void join(StringBuffer before, Object append, String join) {
        if (isEmpty(before)) {
            before.append(append);
        } else {
            before.append(join).append(append);
        }
    }

    /**
     * JAVA 加密
     *
     * @param strSrc  需要加密人字符串，支持中文
     * @param encName 空位MD5，支持MD5 ,SHA-1 SHA-256
     * @return?String
     * @author add by x
     * @date 2013-6-8
     */
    public static String executeMD5(String strSrc) {
        return executeEncrypt(strSrc, null);
    }

    /**
     * JAVA 加密
     *
     * @param strSrc  需要加密人字符串，支持中文
     * @param encName 空位MD5，支持MD5 ,SHA-1 SHA-256
     * @return?String
     * @author add by x
     * @date 2013-6-8
     */
    public static String executeEncrypt(String strSrc, String encName) {
        MessageDigest md = null;
        String strDes = null;

        byte[] bt = strSrc.getBytes();
        try {
            if (encName == null || encName.equals("")) {
                encName = "MD5";
            }
            md = MessageDigest.getInstance(encName);
            md.update(bt);
            strDes = bytes2Hex(md.digest()); // to HexString
        } catch (NoSuchAlgorithmException e) {
            log.error("Invalid algorithm.");
            return null;
        }
        return strDes;
    }


    /***********排序类型的方法用sort开头**************/

    /**
     * 对list中的数据按照字段field就进升序排序
     *
     * @param list
     * @param field
     */
    @SuppressWarnings("all")
    public static void sortAsc(List list, final String field) {
        if (list == null) {
            return;
        }
        Collections.sort(list, new Comparator<Object>() {
            @Override
            public int compare(Object o1, Object o2) {
                try {
                    Object obj = null;
                    Object obj2 = null;
                    if (o1 instanceof Map) {
                        obj = ((Map) o1).get(field);
                        if (CommonUtil.isEmpty(obj)) {
                            return -1;
                        }
                        obj2 = ((Map) o2).get(field);
                        if (CommonUtil.isEmpty(obj2)) {
                            return 1;
                        }
                    } else {
                        obj = ReflectUtil.getFieldValue(o1, field);
                        if (CommonUtil.isEmpty(obj)) {
                            return -1;
                        }
                        obj2 = ReflectUtil.getFieldValue(o2, field);
                        if (CommonUtil.isEmpty(obj2)) {
                            return 1;
                        }
                    }
                    if (obj instanceof String) {
                        return ((String) obj).compareTo((String) obj2);
                    } else if (obj instanceof Number) {
                        return ((Number) obj).longValue() - ((Number) obj2).longValue() > 0 ? 1 : -1;
                    } else if (obj instanceof Date) {
                        return ((Date) obj).getTime() - ((Date) obj2).getTime() > 0 ? 1 : -1;
                    } else {
                        throw new Exception("字段数据类型只能是String,Number和Date");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return 0;
            }
        });
    }

    /**
     * 对list中的数据按照字段field进行降序排序
     *
     * @param list
     * @param field
     */
    @SuppressWarnings("all")
    public static void sortDesc(List list, final String field) {
        if (list == null) {
            return;
        }
        Collections.sort(list, new Comparator<Object>() {
            @Override
            public int compare(Object o1, Object o2) {
                try {
                    Object obj = null;
                    Object obj2 = null;
                    if (o1 instanceof Map) {
                        obj = ((Map) o1).get(field);
                        if (CommonUtil.isEmpty(obj)) {
                            return 1;
                        }
                        obj2 = ((Map) o2).get(field);
                        if (CommonUtil.isEmpty(obj2)) {
                            return -1;
                        }
                    } else {
                        obj = ReflectUtil.getFieldValue(o1, field);
                        if (CommonUtil.isEmpty(obj)) {
                            return 1;
                        }
                        obj2 = ReflectUtil.getFieldValue(o2, field);
                        if (CommonUtil.isEmpty(obj2)) {
                            return -1;
                        }
                    }
                    if (obj instanceof String) {
                        return ((String) obj2).compareTo((String) obj);
                    } else if (obj instanceof Number) {
                        return ((Number) obj2).longValue() - ((Number) obj).longValue() > 0 ? 1 : -1;
                    } else if (obj instanceof Date) {
                        return ((Date) obj2).getTime() - ((Date) obj).getTime() > 0 ? 1 : -1;
                    } else {
                        throw new Exception("字段数据类型只能是String,Number和Date");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return 0;
            }
        });
    }

    /**
     * 对list中的数据进行升序排序
     *
     * @param list
     */
    @SuppressWarnings("all")
    public static void sortAsc(List list) {
        if (isEmpty(list)) {
            return;
        }
        Collections.sort(list, new Comparator<Object>() {
            @Override
            public int compare(Object o1, Object o2) {
                try {
                    Object obj = o1;
                    if (isEmpty(obj)) {
                        return -1;
                    }
                    Object obj2 = o2;
                    if (isEmpty(obj2)) {
                        return 1;
                    }
                    if (obj instanceof String) {
                        return ((String) obj).compareTo((String) obj2);
                    } else if (obj instanceof Number) {
                        return ((Number) obj).longValue() - ((Number) obj2).longValue() > 0 ? 1 : -1;
                    } else if (obj instanceof Date) {
                        return ((Date) obj).getTime() - ((Date) obj2).getTime() > 0 ? 1 : -1;
                    } else {
                        throw new Exception("字段数据类型只能是String,Number和Date");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return 0;
            }
        });
    }

    /**
     * 对list中的数据进行降序排序
     *
     * @param list
     */
    @SuppressWarnings("all")
    public static void sortDesc(List list) {
        if (isEmpty(list)) {
            return;
        }
        Collections.sort(list, new Comparator<Object>() {
            @Override
            public int compare(Object o1, Object o2) {
                try {
                    Object obj = o1;
                    if (isEmpty(obj)) {
                        return 1;
                    }
                    Object obj2 = o2;
                    if (isEmpty(obj2)) {
                        return -1;
                    }
                    if (obj instanceof String) {
                        return ((String) obj2).compareTo((String) obj);
                    } else if (obj instanceof Number) {
                        return ((Number) obj2).longValue() - ((Number) obj).longValue() > 0 ? 1 : -1;
                    } else if (obj instanceof Date) {
                        return ((Date) obj2).getTime() - ((Date) obj).getTime() > 0 ? 1 : -1;
                    } else {
                        throw new Exception("字段数据类型只能是String,Number和Date");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return 0;
            }
        });
    }

    /*************** 复制类型的用copy开头 ******************/

    @SuppressWarnings("all")
    public static <T> List<T> copyListBean(List list_source, Class target_entity_class, String... ignores) {
        if (isEmpty(list_source)) {
            return new ArrayList<T>();
        }
        List<T> ts = new ArrayList<T>();
        for (Object obj : list_source) {
            T target;
            try {
                target = (T) target_entity_class.newInstance();
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                target = null;
            }
            copyBean(obj, target, ignores);
            ts.add(target);
        }
        return ts;
    }


    @SuppressWarnings("unchecked")
    public static <T> T copyBean(Object source, T t, String... ignores) {
        T target;
        try {
            target = (T) t.getClass().newInstance();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return null;
        }
        if (isEmpty(source)) {
            return null;
        }
        try {
            copyBeanProperties(source, target, ignores);
        } catch (Exception e) {
            return null;
        }
        return target;
    }

    public static <T> T copyBean(Object source, Class<T> clazz, String... ignores) {
        T target;
        try {
            target = (T) clazz.newInstance();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return null;
        }
        if (isEmpty(source)) {
            return null;
        }
        try {
            copyBeanProperties(source, target, null);
        } catch (Exception e) {
            return null;
        }
        return target;
    }

    @SuppressWarnings("unchecked")
    public static <T> T copyBean(T source, String... ignores) {
        T target;
        try {
            target = (T) source.getClass().newInstance();
        } catch (Exception e) {
            return null;
        }
        if (isEmpty(source)) {
            return null;
        }
        try {
            copyBeanProperties(source, target, ignores);
        } catch (Exception e) {
            return null;
        }
        return target;
    }


    private static void copyBeanProperties(Object source, Object target, String[] ignores) throws Exception {
        Class<?> actualEditable = target.getClass();
        PropertyDescriptor[] targetPds = BeanUtils.getPropertyDescriptors(actualEditable);
        List<String> ignoreList = (ignores != null) ? Arrays.asList(ignores) : null;
        for (PropertyDescriptor targetPd : targetPds) {
            if (targetPd.getWriteMethod() != null &&
                    (ignores == null || (!ignoreList.contains(targetPd.getName())))) {
                PropertyDescriptor sourcePd = BeanUtils.getPropertyDescriptor(source.getClass(), targetPd.getName());
                if (sourcePd != null && sourcePd.getReadMethod() != null) {
                    Method readMethod = sourcePd.getReadMethod();
                    if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
                        readMethod.setAccessible(true);
                    }
                    Object value = readMethod.invoke(source);
                    Method writeMethod = targetPd.getWriteMethod();
                    if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
                        writeMethod.setAccessible(true);
                    }
                    String type = writeMethod.getParameterTypes()[0].getSimpleName();//参数类型
                    if ("boolean".equals(type)) {
                        boolean booleanVal = false;
                        if ("1".equals(value.toString())) {
                            booleanVal = true;
                        }
                        writeMethod.invoke(target, new Object[]{Boolean.valueOf(booleanVal)});
                        continue;
                    }
                    if ("Timestamp".equals(type)) {
                        if (CommonUtil.isNotEmpty(value)) {
                            Date date = (Date) value;
                            Timestamp ts = new Timestamp(date.getTime());
                            writeMethod.invoke(target, new Object[]{ts});
                        }
                        continue;
                    }
                    writeMethod.invoke(target, value);
                }
            }
        }
    }
    /********** 设置类型的方法以set开头 **************/

    /***
     * 调用底层方法设置值
     */
    public static void setValue(String type, Object value, Method method, Object bean) throws Exception {
        if (value != null && !value.equals("")) {
            if (type.equals("String")) {
                //第一个参数:从中调用基础方法的对象		第二个参数:用于方法调用的参数
                method.invoke(bean, new Object[]{value.toString()});
            } else if (type.equals("int") || type.equals("Integer")) {
                method.invoke(bean, new Object[]{new Integer("" + value)});
            } else if (type.equals("long") || type.equals("Long")) {
                method.invoke(bean, new Object[]{new Long("" + value)});
            } else if (type.equals("BigDecimal")) {
                method.invoke(bean, new Object[]{new BigDecimal("" + value)});
            } else if (type.equals("boolean") || type.equals("Boolean")) {
                //add by x@
                if ("Integer".equals(value.getClass().getSimpleName())) {
                    ;
                    if ((Integer) value == 1) {
                        value = "true";
                    } else {
                        value = "false";
                    }
                }
                method.invoke(bean, new Object[]{Boolean.valueOf("" + value)});
            } else if (type.equals("Date")) {
                Date date = null;
                //modify by x@
                if (value.getClass().getName().equals("java.util.Date")) {
                    date = (Date) value;
                } else if ("String".equals(value.getClass().getSimpleName())) {
                    String tmp = (String) value;
                    if (tmp.indexOf("T") > 0) {
                        tmp = tmp.replace("T", " ");
                    }
                    if (tmp.length() == 10) {
                        tmp = tmp + " 00" + ":" + "00" + ":" + "00";
                    }
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    date = sdf.parse(tmp);
                }
                method.invoke(bean, new Object[]{date});
            } else if (type.equals("byte[]")) {
                method.invoke(bean, new Object[]{new String(value + "").getBytes()});
            }
        }
    }


    /************* 获取类型的方法以get开头 ************/

    /**
     * 清空STRINGBUFFER
     *
     * @param sb
     * @return void
     */
    public static void getClearStringBuffer(StringBuffer sb) {
        sb.delete(0, sb.length());
    }

    /**
     * 对文件流输出下载的中文文件名进行编码 屏蔽各种浏览器版本的差异性
     */
    public static String getChineseDownloadFileName(HttpServletRequest request, String pFileName) {
        String agent = request.getHeader("USER-AGENT");
        try {
            if (null != agent && -1 != agent.indexOf("MSIE")) {
                pFileName = URLEncoder.encode(pFileName, "utf-8");
            } else {
                pFileName = new String(pFileName.getBytes("utf-8"), "iso8859-1");
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return pFileName;
    }

    /**
     * 根据日期获取星期
     *
     * @param strdate
     * @return
     */
    public static String getWeekDayByDate(String strdate) {
        final String dayNames[] = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
        SimpleDateFormat sdfInput = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar = Calendar.getInstance();
        Date date = new Date();
        try {
            date = sdfInput.parse(strdate);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        calendar.setTime(date);
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) - 1;
        if (dayOfWeek < 0)
            dayOfWeek = 0;
        return dayNames[dayOfWeek];
    }

    /**
     * 获得今天周几
     *
     * @return int   Calender.MONDAY 星期一  Calender.THURSDAY 星期二  ...
     */
    public static int getDayOfWeek() {
        return Calendar.getInstance().get(Calendar.DAY_OF_WEEK);
    }

    /**
     * 获得指定时间是周几
     *
     * @return int   Calender.MONDAY 星期一  Calender.THURSDAY 星期二  ...
     */
    public static int getDayOfWeek(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.DAY_OF_WEEK);
    }

    /**
     * 获得随即颜色
     *
     * @return String
     * @author add by x@2012-10-30
     */
    public static String getRandom(int count) {
        String S = "0123456789ABCDEF";
        Random r = new Random();
        String tmp = "";
        for (int i = 0; i < count; i++) {
            int index = r.nextInt(S.length());
            tmp += S.charAt(index);
        }
        return tmp;
    }

    /**
     * 获得随机数字
     *
     * @param count 字符长度
     * @return
     */
    public static String getRandomNumber(int count) {
        String S = "0123456789";
        Random r = new Random();
        String tmp = "";
        for (int i = 0; i < count; i++) {
            int index = r.nextInt(S.length());
            tmp += S.charAt(index);
        }
        return tmp;
    }

    public static String getCurrentDateTime() {
        SimpleDateFormat format = new SimpleDateFormat(COMMON_DATE_FORMAT);
        return format.format(new Date(System.currentTimeMillis()));
    }

    public static String getCurrentDateTimeByFormat(String fmt) {
        SimpleDateFormat format = new SimpleDateFormat(fmt);
        return format.format(new Date(System.currentTimeMillis()));
    }

    /**
     * 随机获取UUID字符串(无中划线)
     *
     * @return UUID字符串
     */
    public static String getUUID() {
        String uuid = UUID.randomUUID().toString();
        return uuid.substring(0, 8) + uuid.substring(9, 13) + uuid.substring(14, 18) + uuid.substring(19, 23) + uuid.substring(24);
    }

    /**
     * 描述
     *
     * @param date1 开始时间
     * @param date2 结束时间
     * @return 返回集合
     * @author zhulc
     * 2013-4-11 下午04:41:45
     */
    @SuppressWarnings("static-access")
    public static List<String> getEndDate(Date date1, Date date2) {
        List<String> list = new ArrayList<String>();
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(date1);
        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(date2);
        long time1 = cal1.getTimeInMillis();
        long time2 = cal2.getTimeInMillis();
        int betweendays = (int) ((time2 - time1) / (1000 * 3600 * 24));
        cal1.add(cal1.DATE, 1);
        SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd");
        //  System.out.println("获取cal1:"+date.format(cal2.getTime()));
        for (int i = 0; i <= betweendays; i++) {
            Calendar caA = Calendar.getInstance();
            caA.setTime(date1);
            //System.out.println("i:"+i);
            //添加日期
            caA.add(cal2.DATE, i);
            Calendar cab = Calendar.getInstance();
            cab.setTime(caA.getTime());
            String week = "";
            int weekDay = cab.get(cab.DAY_OF_WEEK) - 1;
            switch (weekDay) {
                case 0:
                    week = "周日";
                    break;
                case 1:
                    week = "周一";
                    break;
                case 2:
                    week = "周二";
                    break;
                case 3:
                    week = "周三";
                    break;
                case 4:
                    week = "周四";
                    break;
                case 5:
                    week = "周五";
                    break;
                default:
                    week = "周六";
                    break;
            }
            StringBuffer dates = new StringBuffer();
            dates.append(date.format(caA.getTime()));
            dates.append(" ");
            dates.append(week);
            list.add(dates.toString());
            //	System.out.println("获取天数"+date.format(caA.getTime()));
        }
        return list;
    }

    //获取MAC地址的方法
    public static String getMACAddress(InetAddress ia) throws Exception {
        //获得网络接口对象（即网卡），并得到mac地址，mac地址存在于一个byte数组中。
        byte[] mac = NetworkInterface.getByInetAddress(ia).getHardwareAddress();
        //下面代码是把mac地址拼装成String
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < mac.length; i++) {
            if (i != 0) {
                sb.append("-");
            }
            //mac[i] & 0xFF 是为了把byte转化为正整数
            String s = Integer.toHexString(mac[i] & 0xFF);
            sb.append(s.length() == 1 ? 0 + s : s);
        }
        //把字符串所有小写字母改为大写成为正规的mac地址并返回
        return sb.toString().toUpperCase();
    }

    public static String getMAC() {
        String macAddress = "";
        try {
            InetAddress ia = InetAddress.getLocalHost();//获取本地IP对象
            macAddress = getMACAddress(ia);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return macAddress;
    }

    /**
     * getIntervalDays
     * 两个日期间隔的天数
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static int getIntervalDays(Date startDate, Date endDate) {
        int intervalDays = 0;
        Calendar calendarStartDate = Calendar.getInstance();
        Calendar calendarEndDate = Calendar.getInstance();
        calendarStartDate.setTime(startDate);
        calendarEndDate.setTime(endDate);
        //如果开始时间大于结束时间返回0
        if (calendarStartDate.after(calendarEndDate)) {
            return 0;
        } else {
            int intervalYears = calendarEndDate.get(Calendar.YEAR) - calendarStartDate.get(Calendar.YEAR);
            intervalDays = calendarEndDate.get(Calendar.DAY_OF_YEAR) - calendarStartDate.get(Calendar.DAY_OF_YEAR);
            for (int i = 0; i < intervalYears; i++) {
                calendarStartDate.set(Calendar.YEAR, (calendarStartDate.get(Calendar.YEAR) + 1));
                intervalDays += calendarStartDate.getMaximum(Calendar.DAY_OF_YEAR);
            }
            return intervalDays;
        }
    }

    public static String getSqlByClass(Object obj) {
        boolean flag = isNumberForObject(obj);
        boolean time = isTimeForObject(obj);
        if (time) {
            Date date = (Date) obj;
            obj = convertDateToString(date, "yyyy-MM-dd HH:mm:ss.SSS");
        }
        if (flag) {
            return obj + "";
        } else {
            return "'" + obj + "'";
        }
    }

//    /**
//     * 获取集合中对象的值转换成list并且返回
//     *
//     * @param collection
//     * @param key
//     * @return
//     * @throws Exception
//     */
//    public static <T> List<String> getCollectionContentToList(Collection<T> collection, String key) throws Exception {
//        List<String> list = new ArrayList<String>();
//        if (collection == null) {
//            return list;
//        } else {
//            for (T t : collection) {
//                if (t instanceof Map) {
//                    list.add(((Map) t).get(key) + "");
//                } else {//实体类
//                    for (Class<?> superClass = t.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
//                        Field[] fields = superClass.getDeclaredFields();
//                        for (Field field : fields) {
//                            if (field.getName().equalsIgnoreCase(key)) {
//                                PropertyDescriptor pd = new PropertyDescriptor(field.getName(), t.getClass());
//                                Method rM = pd.getReadMethod();//获得读方法
//                                list.add((String) rM.invoke(t));
//                            }
//                        }
//                    }
//                }
//            }
//        }
//
//        return list;
//    }

    /**
     * 获取一个 heder+yyyyMMddHHmmssSSS+4位随机数
     *
     * @param heder
     * @return
     */
    public static String getBillNumber(String heder) {
        return heder + new SimpleDateFormat("yyMMddHHmmssSSS").format(new Date()) + getRandomNumber(4);
    }

    /**
     * @param @param  transNo 单据号类型
     * @param @param  branchNo  操作员的所属门店
     * @param @return
     * @return String    返回一个随机生成的单据号
     * @throws
     * @Title: generateDocumentNum
     * @Description: 生成单据号
     */
    public static String getSheetNo(String transNo, String branchNo) {
        String documentId = transNo + getCurrentDateTimeByFormat("yyMMddHHmm") + getRandomNumber(6);
        return documentId;
    }

    /**
     * 获取对象中字段的值
     *
     * @param fieldName 字段名称
     * @param object对象
     * @return
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    public static <T> T getEntityFieldValue(Object object, String fieldName) throws Exception {
        Field field = object.getClass().getField(fieldName);
        Object obj = field.get(null);
        return (T) obj;
    }

    /********** 添加类型的方法用add开头 **********/
    /**
     * 日期加天数
     *
     * @param date 日期 格式
     * @param days 天数 ：加一天1；减5天 -5
     * @return
     * @return?date
     * @author add by jiaxj
     * @date 2014-7-30
     */
    public static Date addDate(Date date, int days) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, days);
        return calendar.getTime();
    }

    /**
     * 日期加天数
     *
     * @param date 日期 格式yyyy-mm-dd HH:mm:ss
     * @param days 天数
     * @return
     * @return?String yyyy-mm-dd HH:mm:ss
     * @author add by zlc
     * @date 2013-12-10
     */
    public static String addDate(String date, int days) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            Date da = format.parse(date);
            Calendar ca = Calendar.getInstance();
            ca.setTime(da);
            ca.add(Calendar.DATE, days);// 为增加的天数
            da = ca.getTime();
            String backTime = format.format(da);
            return backTime;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 添加一个元素到已有的数据里面去
     *
     * @param array
     * @param element
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] addArrayElement(T[] array, T element) {
        Class type;
        if (array != null) {
            type = array.getClass();
        } else if (element != null) {
            type = element.getClass();
        } else {
            type = Object.class;
        }
        T[] newArray = (T[]) copyArrayGrow1(array, type);
        newArray[newArray.length - 1] = element;
        return newArray;
    }

    /*************** 转换类型的方法用 convert开头 *******************/

    public static Integer convertStringToInteger(String str) {
        if (isEmpty(str)) {
            return null;
        } else {
            return new BigDecimal(str.trim()).intValue();
        }
    }

    public static BigDecimal convertStringToBigDecimal(String str) {
        if (isEmpty(str)) {
            return BigDecimal.ZERO;
        } else {
            return new BigDecimal(str.trim());
        }
    }

    /**
     * 将一个 Map 对象转化为一个 JavaBean
     *
     * @param clazz 要转化的类型
     * @param map   包含属性值的 map
     * @return 转化出来的 JavaBean 对象
     * @throws IntrospectionException    如果分析类属性失败
     * @throws IllegalAccessException    如果实例化 JavaBean 失败
     * @throws InstantiationException    如果实例化 JavaBean 失败
     * @throws InvocationTargetException 如果调用属性的 setter 方法失败
     */
    @SuppressWarnings("unchecked")
    public static <T> T convertMapToBean(Map map, Class<T> clazz) {
        if (map == null) {
            return null;
        }
        Object obj;
        try {
            obj = clazz.newInstance();
            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                Method setter = property.getWriteMethod();
                try {
                    if (setter != null) {
                        Object object = map.get(property.getName());
                        if (isNotEmpty(object)) {
                            if (object instanceof Date) {
                                setter.invoke(obj, object);
                            } else {
                                Constructor constructor = property.getPropertyType().getConstructor(String.class);
                                setter.invoke(obj, constructor.newInstance(object.toString()));
                            }
                        }
                    }
                } catch (Exception e) {
                    log.error(property.getName() + "[" + map.get(property.getName()).getClass() + "]不能转换成-->" + property.getPropertyType());
                    throw e;
                }
            }
            return (T) obj;
        } catch (Exception e) {
            log.error("Map --> Object 转换错误", e);
            return null;
        }
    }

    /**
     * format yyyy-MM-dd HH:mm:ss
     *
     * @param str
     * @return
     * @throws ParseException
     */
    public static Date convertStringToDate(String str) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String strDate = str;
        return sdf.parse(strDate);
    }

    /**
     * format yyyy-MM-dd
     *
     * @param str
     * @return
     * @throws ParseException
     */
    public static Date convertStringToOnlyDate(String str) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String strDate = str;
        return sdf.parse(strDate);
    }

    /**
     * @param str format
     * @return
     * @throws ParseException
     */
    public static Date convertStringToDate(String str, String format) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        String strDate = str;
        return sdf.parse(strDate);
    }

    /**
     * 将对象转换为JSON字符串
     *
     * @param object 对象
     */
    public static String convertObjectToJson(Object object) {
        if (isEmpty(object)) {
            return null;
        }
        try {
            ObjectMapper mapper = new ObjectMapper();
            mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
            return mapper.writeValueAsString(object);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    public static String convertDateToString(Date date, String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(date);
    }

//    /**
//     * 将json 字符串转成list<T>
//     *
//     * @param text
//     * @param clazz
//     * @return
//     */
//    @SuppressWarnings("unchecked")
//    public static <T> List<T> convertJsonToBean(String text, Class clazz) {
//        return JSONArray.parseArray(text, clazz);
//    }

    /**
     * 将JSON字符串转换为对象
     *
     * @param json      JSON字符串
     * @param valueType 对象类型
     */
    @SuppressWarnings("deprecation")
    public static <T> T convertJsonToObject(String json, Class<T> valueType) {
        Assert.notNull(json);
        Assert.notNull(valueType);
        try {
            return mapper.readValue(json, valueType);
        } catch (Exception e) {
            log.error(json, e);
            log.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 将JSON字符串转换为对象
     *
     * @param json        JSON字符串
     * @param contentType 对象类型(返回对象类型)
     * @return List
     */
    public static <T> List<T> convertJsonToObjectList(String json, Class<T> contentType) {
        List list = convertJsonToObject(json, List.class);
        if (isEmpty(list)) {
            return null;
        }
        List<T> rlist = new ArrayList<T>();
        for (Object obj : list) {
            Map map = (Map) obj;
            T t = convertMapToBean(map, contentType);
            rlist.add(t);
        }
        return rlist;
    }

    /**
     * 将一个 JavaBean 对象转化为一个  Map
     *
     * @param bean 要转化的JavaBean 对象
     * @return 转化出来的  Map 对象
     * @throws IntrospectionException    如果分析类属性失败
     * @throws IllegalAccessException    如果实例化 JavaBean 失败
     * @throws InvocationTargetException 如果调用属性的 setter 方法失败
     */
    @SuppressWarnings("unchecked")
    public static Map<String, Object> convertBeanToMap(Object bean) throws Exception {
        if (isEmpty(bean)) {
            return null;
        }
        Map returnMap = new HashMap();
        Class type = bean.getClass();
        BeanInfo beanInfo = Introspector.getBeanInfo(type);

        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        for (int i = 0; i < propertyDescriptors.length; i++) {
            PropertyDescriptor descriptor = propertyDescriptors[i];
            String propertyName = descriptor.getName();
            if (!propertyName.equals("class")) {
                Method readMethod = descriptor.getReadMethod();
                Object result = readMethod.invoke(bean, new Object[0]);
                if (result != null) {
                    returnMap.put(propertyName, result);
                } else {
                    returnMap.put(propertyName, "");
                }
            }
        }
        return returnMap;
    }

    /**
     * 将java类型转换成数据库的类型
     *
     * @param clazz
     * @return
     * @throws Exception
     */
    public static String convertJavaTypeToDb(Class clazz) throws Exception {
        if (clazz.equals(String.class)) {
            return "VARCHAR";
        } else if (clazz.equals(BigDecimal.class)) {
            return "NUMERIC";
        } else if (clazz.equals(Boolean.class) || clazz.equals(boolean.class)) {
            return "BIT";
        } else if (clazz.equals(Integer.class) || clazz.equals(int.class)) {
            return "INTEGER";
        } else if (clazz.equals(Long.class) || clazz.equals(long.class)) {
            return "BIGINT";
        } else if (clazz.equals(Float.class) || clazz.equals(float.class)) {
            return "REAL";
        } else if (clazz.equals(Double.class) || clazz.equals(double.class)) {
            return "DOUBLE";
        } else if (clazz.equals(Byte[].class) || clazz.equals(byte[].class)) {
            return "VARBINARY";
        } else if (clazz.equals(java.sql.Date.class) || clazz.equals(Date.class)) {
            return "TIMESTAMP";
        } else if (clazz.equals(Time.class)) {
            return "TIMESTAMP";
        } else if (clazz.equals(Timestamp.class)) {
            return "TIMESTAMP";
        } else {
            throw new Exception("java类--->" + clazz + "没有找到对应的数据库属性");
        }
    }

    /**
     * 将数据库类型转换成java类型
     *
     * @param dbType
     * @return
     * @throws Exception
     */
    public static Class convertDBTypeToJavaClass(String dbType) throws Exception {
        if (dbType.equals("CHAR")) {
            return String.class;
        } else if (dbType.equals("VARCHAR")) {
            return String.class;
        } else if (dbType.equals("LONGVARCHAR")) {
            return String.class;
        } else if (dbType.equals("NUMERIC")) {
            return BigDecimal.class;
        } else if (dbType.equals("DECIMAL")) {
            return BigDecimal.class;
        } else if (dbType.equals("BIT")) {
            return Boolean.class;
        } else if (dbType.equals("TINYINT")) {
            return Byte.class;
        } else if (dbType.equals("SMALLINT")) {
            return Short.class;
        } else if (dbType.equals("INTEGER")) {
            return Integer.class;
        } else if (dbType.equals("BIGINT")) {
            return Long.class;
        } else if (dbType.equals("REAL")) {
            return Float.class;
        } else if (dbType.equals("FLOAT")) {
            return Double.class;
        } else if (dbType.equals("DOUBLE")) {
            return Double.class;
        } else if (dbType.equals("BINARY")) {
            return Byte[].class;
        } else if (dbType.equals("VARBINARY")) {
            return Byte[].class;
        } else if (dbType.equals("LONGVARBINARY")) {
            return Byte[].class;
        } else if (dbType.equals("DATE")) {
            return Date.class;
        } else if (dbType.equals("TIME")) {
            return Date.class;
        } else if (dbType.equals("TIMESTAMP")) {
            return Date.class;
        } else if (dbType.equals("DATETIME")) {
            return Date.class;
        } else if (dbType.equals("INT")) {
            return Integer.class;
        } else {
            throw new Exception("dbTypeToJava:数据库类型--->" + dbType + "没有找到对应的java类");
        }
    }

    /**
     * 驼峰字符串转化成_
     * bd_item_info--->BdItemInfo
     *
     * @param
     * @return String
     */
    public static String convertDBToHump(String str) {
        StringBuffer sb = new StringBuffer();
        String[] fields = str.split("_");
        String temp = null;
        for (int i = 0; i < fields.length; i++) {
            temp = fields[i].trim();
            sb.append(temp.substring(0, 1).toUpperCase()).append(temp.substring(1));
        }
        return sb.toString();
    }

    /**
     * 将驼峰数据转换为正常数据，去除_ 变大写
     * BdItemInfo--->bd_item_info或者bdItemInfo--->bd_item_info
     *
     * @param
     * @return
     */
    public static String convertHumpToDB(String str) {
        String first = str.substring(0, 1).toLowerCase();
        String last = str.substring(1);
        StringBuilder tmp = new StringBuilder();
        for (int i = 0; i < last.length(); i++) {
            if (Character.isUpperCase(last.charAt(i))) {
                tmp.append("_" + last.substring(i, i + 1).toLowerCase());
            } else {
                tmp.append(last.substring(i, i + 1));
            }
        }
        return first + tmp.toString();
    }

    /**
     * 驼峰字符串转化成_
     * bd_item_info--->bdItemInfo
     *
     * @param
     * @return String
     */
    public static String convertDBToFistLowercaseHump(String str) {
        StringBuffer sb = new StringBuffer();
        String[] fields = str.split("_");
        String temp = null;
        for (int i = 0; i < fields.length; i++) {
            temp = fields[i].trim();
            if (i == 0) {
                sb.append(temp.substring(0, 1).toLowerCase()).append(temp.substring(1));
            } else {
                sb.append(temp.substring(0, 1).toUpperCase()).append(temp.substring(1));
            }
        }
        return sb.toString();
    }

    /**
     * c.BsIs-->c.bs_is
     * abcD-->abc_d
     * AbcD-->abc_d
     *
     * @param sql
     * @return
     */
    public static String convertStringToSql(String str) {
        if (str.contains(".")) {
            str = str.split("\\.")[0] + "." + CommonUtil.convertHumpToDB(str.split("\\.")[1]);
        } else {
            str = CommonUtil.convertHumpToDB(str);
        }
        return str;
    }

    /**
     * 把集合中的数据 拼装成 where in 的条件
     *
     * @param collection 条件结合
     * @param clazz      集合中数据的类型
     * @param key        获取类型中数据的key,当为实体类是 key 为字段名称
     * @return
     * @throws Exception
     */
    public static String convertCollectionToWhereInSql(Collection collection, Class clazz, String key) throws Exception {
        StringBuffer sql = new StringBuffer();
        if (isEmpty(collection)) {
            throw new Exception("出入的 in 语句 的参数不能为 空");
        } else {
            Iterator it = collection.iterator();
            while (it.hasNext()) {
                Object obj = it.next();
                Object robj = new Object();
                if (isNotEmpty(clazz) && isNotEmpty(key)) {
                    if (clazz.equals(Map.class)) {
                        Map map = (Map) obj;
                        robj = map.get(key);
                    } else {
                        PropertyDescriptor pd = new PropertyDescriptor(key, clazz);
                        Method getMethod = pd.getReadMethod();//获得get方法
                        robj = getMethod.invoke(obj);//执行get方法返回一个Object
                    }
                } else {
                    robj = obj;
                }
                if (isNumberForObject(robj)) {
                    if (sql.length() == 0) {
                        sql.append("" + obj + "");
                    } else {
                        sql.append("," + obj + "");
                    }
                } else {
                    if (sql.length() == 0) {
                        sql.append("'" + obj + "'");
                    } else {
                        sql.append(",'" + obj + "'");
                    }
                }
            }
        }
        return "in (" + sql.toString() + ")";
    }

    /**
     * 拼装 in条件
     *
     * @param String[] strs
     * @return
     * @throws Exception
     */
    public static String convertArrayToWhereInSql(String[] strs) throws Exception {
        StringBuffer sql = new StringBuffer();
        if (isEmpty(strs)) {
            throw new Exception("出入的 in 语句 的参数不能为 空");
        } else {
            for (String str : strs) {
                if (sql.length() == 0) {
                    sql.append("'" + str + "'");
                } else {
                    sql.append(",'" + str + "'");
                }
            }
        }
        return "in (" + sql.toString() + ")";
    }

    /**
     * 把传入的字符串 转化成where xxx in (xxx) 的形式，
     *
     * @param str 1,2,3,4
     * @return String
     * @return (' 1 ', ' 2 ', ' 3 ', ' 4 ')
     * @author add by x@2012-9-17
     */
    public static String convertContainCommaStringToWhereIn(String str) {
        if (str == null || "".equals(str)) return "('')";

        if (str.indexOf(",") > 0) {
            String[] list = str.split(",");
            StringBuffer sb = new StringBuffer("(");
            for (int i = 0; i < list.length; i++) {
                sb.append("'" + list[i] + "'");
                if (i != list.length - 1) {
                    sb.append(",");
                }
            }
            sb.append(")");
            return sb.toString();
        } else {
            return "('" + str + "')";
        }
    }

    /******************  判断/验证,类型的方法用is开头  ********************/
    public static boolean isNotEmpty(Object pObj) {
        return !isEmpty(pObj);
    }

    /**
     * 判断对象是否Empty(null或元素为0)<br>
     * 实用于对如下对象做判断:String Collection及其子类 Map及其子类
     *
     * @param pObj 待检查对象
     * @return boolean 返回的布尔值
     */
    public static boolean isEmpty(Object pObj) {
        if (pObj == null)
            return true;
        if (pObj == "")
            return true;
        if (pObj instanceof String) {
            if (((String) pObj).length() == 0) {
                return true;
            }
        } else if (pObj instanceof Collection) {
            if (((Collection) pObj).size() == 0) {
                return true;
            }
        } else if (pObj instanceof Map) {
            if (((Map) pObj).size() == 0) {
                return true;
            }
        } else if (pObj instanceof StringBuffer) {
            if (((StringBuffer) pObj).length() == 0) {
                return true;
            }
        }
        return false;
    }

    /**
     * 是否为数字类型
     *
     * @param obj
     * @return
     */
    public static Boolean isNumberForObject(Object obj) {
        Boolean flag = false;
        if (obj instanceof Integer || obj instanceof Long ||
                obj instanceof Double || obj instanceof Short ||
                obj instanceof Float || obj instanceof BigDecimal) {
            flag = true;
        }
        return flag;
    }

    /**
     * 是否为时间类型
     *
     * @param obj
     * @return
     */
    public static Boolean isTimeForObject(Object obj) {
        if (obj instanceof Date) {
            return true;
        }
        return false;
    }

    /**
     * 是否为数字类型
     *
     * @param Class
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    public static Boolean isNumberForClass(Class clazz) {
        try {
            Constructor constructor = clazz.getConstructor(String.class);
            if (constructor.newInstance("0") instanceof Number) {
                return true;
            }
        } catch (Exception e) {
            return false;
        }
        return false;
    }

    /**
     * 是否为日期类型
     *
     * @param Class
     * @return
     * @throws Exception
     */
    public static Boolean isTimeForClass(Class clazz) {
        try {
            if (clazz.newInstance() instanceof Date) {
                return true;
            }
        } catch (Exception e) {
            return false;
        }
        return false;
    }

    /**
     * 验证这个类是否有长度
     *
     * @param dbType
     * @return
     * @throws Exception
     */
    public static boolean isLengthForDb(String dbType) throws Exception {
        if (dbType.equals("CHAR")) {
            return true;
        } else if (dbType.equals("VARCHAR")) {
            return true;
        } else if (dbType.equals("LONGVARCHAR")) {
            return true;
        } else if (dbType.equals("NUMERIC")) {
            return true;
        } else if (dbType.equals("DECIMAL")) {
            return true;
        } else if (dbType.equals("BIT")) {
            return false;
        } else if (dbType.equals("TINYINT")) {
            return true;
        } else if (dbType.equals("SMALLINT")) {
            return true;
        } else if (dbType.equals("INTEGER")) {
            return true;
        } else if (dbType.equals("BIGINT")) {
            return true;
        } else if (dbType.equals("REAL")) {
            return true;
        } else if (dbType.equals("FLOAT")) {
            return true;
        } else if (dbType.equals("DOUBLE")) {
            return true;
        } else if (dbType.equals("BINARY")) {
            return false;
        } else if (dbType.equals("VARBINARY")) {
            return false;
        } else if (dbType.equals("LONGVARBINARY")) {
            return false;
        } else if (dbType.equals("DATE")) {
            return false;
        } else if (dbType.equals("TIME")) {
            return false;
        } else if (dbType.equals("TIMESTAMP")) {
            return false;
        } else if (dbType.equals("DATETIME")) {
            return false;
        } else if (dbType.equals("INT")) {
            return true;
        } else {
            throw new Exception("checkLength:验证长度--->" + dbType + "没有找到对应的java类");
        }
    }

    /**
     * 验证这个类是否有小数位
     *
     * @param dbType 数据库类型
     * @return
     * @throws Exception
     */
    public static boolean isDecimalForDB(String dbType) throws Exception {
        if (dbType.equals("CHAR")) {
            return false;
        } else if (dbType.equals("VARCHAR")) {
            return false;
        } else if (dbType.equals("LONGVARCHAR")) {
            return false;
        } else if (dbType.equals("NUMERIC")) {
            return true;
        } else if (dbType.equals("DECIMAL")) {
            return true;
        } else if (dbType.equals("BIT")) {
            return false;
        } else if (dbType.equals("TINYINT")) {
            return false;
        } else if (dbType.equals("SMALLINT")) {
            return false;
        } else if (dbType.equals("INTEGER")) {
            return false;
        } else if (dbType.equals("BIGINT")) {
            return false;
        } else if (dbType.equals("REAL")) {
            return false;
        } else if (dbType.equals("FLOAT")) {
            return true;
        } else if (dbType.equals("DOUBLE")) {
            return true;
        } else if (dbType.equals("BINARY")) {
            return false;
        } else if (dbType.equals("VARBINARY")) {
            return false;
        } else if (dbType.equals("LONGVARBINARY")) {
            return false;
        } else if (dbType.equals("DATE")) {
            return false;
        } else if (dbType.equals("TIME")) {
            return false;
        } else if (dbType.equals("TIMESTAMP")) {
            return false;
        } else if (dbType.equals("DATETIME")) {
            return false;
        } else if (dbType.equals("INT")) {
            return false;
        } else {
            throw new Exception("checkLength:验证长度--->" + dbType + "没有找到对应的java类");
        }
    }

    public static String isEmptyReturnNull(String param) {
        return isEmpty(param) ? null : param;
    }

    public static BigDecimal isEmptyReturnNull(BigDecimal param) {
        return isEmpty(param) ? null : param;
    }

    public static Object isEmptyReturnNull(Object param) {
        return isEmpty(param) ? null : param;
    }

    public static String isEmptyReturnEmpty(Object param) {
        return isEmpty(param) ? "" : (String) param;
    }

    public static BigDecimal isEmptyReturnZero(BigDecimal param) {
        return isEmpty(param) ? BigDecimal.ZERO : param;
    }

    public static int isEmptyReturnZero(List param) {
        return isEmpty(param) ? 0 : param.size();
    }

    public static <T> T isEmptyReturn(Object param, T returnValue) {
        return isEmpty(param) ? returnValue : (T) param;
    }

    public static <T> T isEmptyReturn(Object param, T emptyValue, T notEmptyValue) {
        return isEmpty(param) ? emptyValue : notEmptyValue;
    }

    /*******私有方法区域*********/

    private static Object copyArrayGrow1(Object array, Class newArrayComponentType) {
        if (array != null) {
            int arrayLength = Array.getLength(array);
            Object newArray = Array.newInstance(array.getClass().getComponentType(), arrayLength + 1);
            System.arraycopy(array, 0, newArray, 0, arrayLength);
            return newArray;
        }
        return Array.newInstance(newArrayComponentType, 1);
    }

    private static String bytes2Hex(byte[] bts) {
        String des = "";
        String tmp = null;
        for (int i = 0; i < bts.length; i++) {
            tmp = (Integer.toHexString(bts[i] & 0xFF));
            if (tmp.length() == 1) {
                des += "0";
            }
            des += tmp;
        }
        return des;
    }

    public static boolean isIn(String object, Object... targets) {
        if (isEmpty(object) || isEmpty(targets) || targets.length == 0) {
            return false;
        }
        for (Object obj : targets) {
            if (object.equals(obj)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取访问者IP
     * 在一般情况下使用Request.getRemoteAddr()即可，但是经过nginx等反向代理软件后，这个方法会失效。
     * <p>
     * 本方法先从Header中获取X-Real-IP，如果不存在再从X-Forwarded-For获得第一个IP(用,分割)，
     * 如果还不存在则调用Request .getRemoteAddr()。
     *
     * @param request
     * @return
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("X-Real-IP");
        if (ip != null && !"".equals(ip) && !"unknown".equalsIgnoreCase(ip)) {
            return ip;
        }
        ip = request.getHeader("X-Forwarded-For");
        if (ip != null && !"".equals(ip) && !"unknown".equalsIgnoreCase(ip)) {
            // 多次反向代理后会有多个IP值，第一个为真实IP。
            int index = ip.indexOf(',');
            if (index != -1) {
                return ip.substring(0, index);
            } else {
                return ip;
            }
        } else {
            return request.getRemoteAddr();
        }
    }

    /**
     * 获取来访者的浏览器版本
     *
     * @param request
     * @return
     */
    public static String getRequestBrowserInfo(HttpServletRequest request) {
        String browserVersion = null;
        String header = request.getHeader("user-agent");
        if (header == null || header.equals("")) {
            return "";
        }
        if (header.indexOf("MSIE") > 0) {
            browserVersion = "IE";
        } else if (header.indexOf("Firefox") > 0) {
            browserVersion = "Firefox";
        } else if (header.indexOf("Chrome") > 0) {
            browserVersion = "Chrome";
        } else if (header.indexOf("Safari") > 0) {
            browserVersion = "Safari";
        } else if (header.indexOf("Camino") > 0) {
            browserVersion = "Camino";
        } else if (header.indexOf("Konqueror") > 0) {
            browserVersion = "Konqueror";
        }
        return browserVersion;
    }

    /**
     * 获取系统版本信息
     *
     * @param request
     * @return
     */
    public static String getRequestSystemInfo(HttpServletRequest request) {
        String systenInfo = null;
        String header = request.getHeader("user-agent");
        if (header == null || header.equals("")) {
            return "";
        }
        //得到用户的操作系统
        if (header.indexOf("NT 6.0") > 0) {
            systenInfo = "Windows Vista/Server 2008";
        } else if (header.indexOf("NT 5.2") > 0) {
            systenInfo = "Windows Server 2003";
        } else if (header.indexOf("NT 5.1") > 0) {
            systenInfo = "Windows XP";
        } else if (header.indexOf("NT 6.0") > 0) {
            systenInfo = "Windows Vista";
        } else if (header.indexOf("NT 6.1") > 0) {
            systenInfo = "Windows 7";
        } else if (header.indexOf("NT 6.2") > 0) {
            systenInfo = "Windows Slate";
        } else if (header.indexOf("NT 6.3") > 0) {
            systenInfo = "Windows 9";
        } else if (header.indexOf("NT 5") > 0) {
            systenInfo = "Windows 2000";
        } else if (header.indexOf("NT 4") > 0) {
            systenInfo = "Windows NT4";
        } else if (header.indexOf("Me") > 0) {
            systenInfo = "Windows Me";
        } else if (header.indexOf("98") > 0) {
            systenInfo = "Windows 98";
        } else if (header.indexOf("95") > 0) {
            systenInfo = "Windows 95";
        } else if (header.indexOf("Mac") > 0) {
            systenInfo = "Mac";
        } else if (header.indexOf("Unix") > 0) {
            systenInfo = "UNIX";
        } else if (header.indexOf("Linux") > 0) {
            systenInfo = "Linux";
        } else if (header.indexOf("SunOS") > 0) {
            systenInfo = "SunOS";
        }
        return systenInfo;
    }

    /**
     * 获取来访者的主机名称
     *
     * @param ip
     * @return
     */
    public static String getHostName(String ip) {
        InetAddress inet;
        try {
            inet = InetAddress.getByName(ip);
            return inet.getHostName();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 命令获取mac地址
     *
     * @param cmd
     * @return
     */
    private static String callCmd(String[] cmd) {
        String result = "";
        String line = "";
        try {
            Process proc = Runtime.getRuntime().exec(cmd);
            InputStreamReader is = new InputStreamReader(proc.getInputStream());
            BufferedReader br = new BufferedReader(is);
            while ((line = br.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * @param cmd     第一个命令
     * @param another 第二个命令
     * @return 第二个命令的执行结果
     */

    private static String callCmd(String[] cmd, String[] another) {
        String result = "";
        String line = "";
        try {
            Runtime rt = Runtime.getRuntime();
            Process proc = rt.exec(cmd);
            proc.waitFor(); // 已经执行完第一个命令，准备执行第二个命令
            proc = rt.exec(another);
            InputStreamReader is = new InputStreamReader(proc.getInputStream());
            BufferedReader br = new BufferedReader(is);
            while ((line = br.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * @param ip           目标ip,一般在局域网内
     * @param sourceString 命令处理的结果字符串
     * @param macSeparator mac分隔符号
     * @return mac地址，用上面的分隔符号表示
     */

    private static String filterMacAddress(final String ip, final String sourceString, final String macSeparator) {
        String result = "";
        String regExp = "((([0-9,A-F,a-f]{1,2}" + macSeparator + "){1,5})[0-9,A-F,a-f]{1,2})";
        Pattern pattern = Pattern.compile(regExp);
        Matcher matcher = pattern.matcher(sourceString);
        while (matcher.find()) {
            result = matcher.group(1);
            if (sourceString.indexOf(ip) <= sourceString.lastIndexOf(matcher.group(1))) {
                break; // 如果有多个IP,只匹配本IP对应的Mac.
            }
        }
        return result;
    }

    /**
     * @param ip 目标ip
     * @return Mac Address
     */

    private static String getMacInWindows(final String ip) {
        String result = "";
        String[] cmd = {"cmd", "/c", "ping " + ip};
        String[] another = {"cmd", "/c", "arp -a"};
        String cmdResult = callCmd(cmd, another);
        result = filterMacAddress(ip, cmdResult, "-");
        return result;
    }

    /**
     * @param ip 目标ip
     * @return Mac Address
     */
    private static String getMacInLinux(final String ip) {
        String result = "";
        String[] cmd = {"/bin/sh", "-c", "ping " + ip + " -c 2 && arp -a"};
        String cmdResult = callCmd(cmd);
        result = filterMacAddress(ip, cmdResult, ":");
        return result;
    }

    /**
     * 获取MAC地址
     *
     * @return 返回MAC地址
     */
    public static String getMacAddress(String ip) {
        String macAddress = "";
        macAddress = getMacInWindows(ip).trim();
        if (macAddress == null || "".equals(macAddress)) {
            macAddress = getMacInLinux(ip).trim();
        }
        return macAddress;
    }

    public static String getReleaseNo() {
        return "tg" + DateUtil.getAllTime() + getRandomNumber(6);
    }

    public static int eq(BigDecimal b1, BigDecimal b2) {
        return b1.setScale(2, RoundingMode.HALF_UP).compareTo(b2.setScale(2, RoundingMode.HALF_UP));
    }

    public static boolean eqt(BigDecimal b1, BigDecimal b2) {
        return b1.setScale(2, RoundingMode.HALF_UP).compareTo(b2.setScale(2, RoundingMode.HALF_UP)) == 0;
    }

    public static boolean lt(BigDecimal b1, BigDecimal b2) {
        return b1.setScale(2, RoundingMode.HALF_UP).compareTo(b2.setScale(2, RoundingMode.HALF_UP)) == -1;
    }

    public static boolean ltq(BigDecimal b1, BigDecimal b2) {
        return b1.setScale(2, RoundingMode.HALF_UP).compareTo(b2.setScale(2, RoundingMode.HALF_UP)) < 1;
    }

    public static boolean gt(BigDecimal b1, BigDecimal b2) {
        return b1.setScale(2, RoundingMode.HALF_UP).compareTo(b2.setScale(2, RoundingMode.HALF_UP)) == 1;
    }

    public static boolean gtq(BigDecimal b1, BigDecimal b2) {
        return b1.setScale(2, RoundingMode.HALF_UP).compareTo(b2.setScale(2, RoundingMode.HALF_UP)) > -1;
    }

    public static String getStackMsg(Exception e) {
        StringWriter sw = new StringWriter();
        e.printStackTrace(new PrintWriter(sw, true));
        String strs = sw.toString();
        return strs;
    }

    private static final SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static String formatYmdHms(Date date) {
        if (date == null)
            return "";
        return f.format(date);
    }
}
